//@author A0100939H
//@class Tokeniser
//@Description This class tokenises the user input string, it is part of the logic.
///				Tokeniser handles the following operations
///				1. Tokeniser object contains the command type, Entry and user input
///				2. Based on user command, Tokeniser returns different things
///				- returns Entry* if command is "add"
///				- returns line number if command is "delete"
///				- returns a string of keywords if command is "search"
///				- returns a vector containing the part of Entry to be editted if command is "edit"
///				- returns command type when BOTLogic calls for it
///				3. Tokeniser also checks the format user input (utilised by GUI)
///				4. BOTLogic uses Tokeniser to format date string to QDate as well


#ifndef _TOKENISER_H_
#define _TOKENISER_H_	


#include "Entry.h"
#include "Event.h"
#include "Task.h"
#include "CommonUtils.h"
#include "CommonEnum.h"

#include <BotException.h>
#include <assert.h>
#include <Entry.h>
#include <Event.h>
#include <Task.h>
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <stdio.h>
#include <qdatetime.h>
#include <qstring.h>
#include <QDebug>
#include <regex>

using namespace std;

class Tokeniser
{
private:
	Entry* _newEntry;
	string _textLine;
	CommonEnum::COMMAND_TYPE _command;

	static const char* KEYWORD_AT;
	static const char* KEYWORD_ON;
	static const char* KEYWORD_BY;
	static const char* KEYWORD_FROM;
	static const char* KEYWORD_TO;

	static const char* KEYWORD_EDIT_NAME;
	static const char* KEYWORD_EDIT_START_TIME;
	static const char* KEYWORD_EDIT_END_TIME;
	static const char* KEYWORD_EDIT_START_DATE;
	static const char* KEYWORD_EDIT_END_DATE;

	static const string DATE;
	static const string TIME;
	static const string DATE_TIME_INVALID;
	static const string TODAY;
	static const string TOMORROW;

	static const string QUOTE;
	static const string STRING_EMPTY;
	static const int SIZE_VECTOR;

	static const QTime TIME_MIDNIGHT;
	static const QTime TIME_BEFORE_MIDNIGHT;

	static const char* DATE_TYPE_ARMY;
	static const char* DATE_TYPE_SHORT_TYPE_1;
	static const char* DATE_TYPE_SHORT_TYPE_2;
	static const char* DATE_TYPE_DAY_TYPE_1;
	static const char* DATE_TYPE_DAY_TYPE_2;

	static const QDate DATE_CURRENT;
	static const char* DATE_FORMAT_ARMY;
	static const char* DATE_FORMAT_DAY;
	static const char* DATE_FORMAT_SHORT_TYPE_1;
	static const char* DATE_FORMAT_SHORT_TYPE_2;
	static const char* DATE_TODAY;
	static const char* DATE_TOMORROW;

	static const char* TIME_TYPE_12_HOUR;
	static const char* TIME_TYPE_24_HOUR_TYPE_1;
	static const char* TIME_TYPE_24_HOUR_TYPE_2;
	
	static const char* TIME_FORMAT_12_HOUR;
	static const char* TIME_FORMAT_24_HOUR_TYPE_1;
	static const char* TIME_FORMAT_24_HOUR_TYPE_2;
	
	static const char* CMD_FORMAT_QUOTE_TYPE_1;
	static const char* CMD_FORMAT_QUOTE_TYPE_2;
	static const char* CMD_FORMAT_FLOATING;

	static const char* CMD_FORMAT_ADD_FLOATING;
	static const char* CMD_FORMAT_ADD_DATE;
	static const char* CMD_FORMAT_ADD_DATETIME;
	static const char* CMD_FORMAT_ADD_TIME;
	static const char* CMD_FORMAT_ADD_TIMETIME;
	static const char* CMD_FORMAT_ADD_DATEDATE;
	static const char* CMD_FORMAT_ADD_DATETIMETIME;
	static const char* CMD_FORMAT_ADD_DATETIMEDATETIME;
	static const char* CMD_FORMAT_ADD_RELATIVEDAY_TYPE_1;
	static const char* CMD_FORMAT_ADD_RELATIVEDAY_TYPE_2;
	static const char* CMD_FORMAT_ADD_RELATIVEDAY_TYPE_3;
	static const char* CMD_FORMAT_ADD_QUOTE;

	static const char* CMD_FORMAT_EDIT_NAME;
	static const char* CMD_FORMAT_EDIT_TIME;
	static const char* CMD_FORMAT_EDIT_DATE;

	static const char* CMD_FORMAT_DELETE;
	static const char* CMD_FORMAT_DISPLAY;
	static const char* CMD_FORMAT_SEARCH;
	static const char* CMD_FORMAT_REDO;
	static const char* CMD_FORMAT_UNDO;
	static const char* CMD_FORMAT_HELP;
	static const char* CMD_FORMAT_CLEAR;
	static const char* CMD_FORMAT_EXIT;
	static const char* CMD_FORMAT_DONE;
	static const char* CMD_FORMAT_EVENT;

	//This function extracts the command type
	//Pre-req: string of user input
	//Post-req: returns the common type
	CommonEnum::COMMAND_TYPE extractCommand();

	//This function packages the name, date(if there is), time(if there is) into a vector
	//Pre-req: vector for the name, date(if there is), time(if there is) to be pushed in
	//Post-req: NIL
	void extractAndPackage(vector <string>&);

	//This function extracts the task when entry is of task type
	//Pre-req: vector of the name, date(if there is), time(if there is)
	//Post-req: NIL
	void extractTask(vector<string>);

	//This function extracts the event when entry is of event type
	//Pre-req: vector of the name, date(if there is), time(if there is)
	//Post-req: NIL
	void extractEvent(vector<string>);

	//This function checks if the entry is valid and throw exceptions if it is not
	//Pre-req: NIL
	//Post-req: NIL
	void validateEntry();

	//This function extracts the entry by creating Task or Event
	//Pre-req: NIL
	//Post-req: returns the whole entry
	Entry* extractEntry();

	//This function formats the time from a string to a QTime
	//Pre-req: time string
	//Post-req: returns time format of QTime
	QTime formatTime(string);

	//This function checks if a string is empty
	//Pre-req: any string to be checked, usually the name of the entry
	//Post-req: returns true if string is empty and false if not empty
	bool isEmpty(string);

	//This function extracts the first word from a string
	//Pre-req: any string
	//Post-req: returns the same string but wthout the first word
	string extractFirstWord(string);

	//This function extracts the content in between quotation marks
	//Pre-req: any string
	//Post-req: returns the string within the quotation marks
	string extractNameInQuote(string&); 

	//This function extracts the name of entry
	//Pre-req: string of user input
	//Post-req: returns name of entry
	string extractName(string&);

	//This function extracts the relative day eg today or tomorrow
	//Pre-req: any string, usually user input
	//Post-req: returns either "today" or "tomorrow", whichever is present in the string
	string extractRelativeDay(string&);

	//This function checks the number of keywords in the string eg on, by, to, from, at
	//Pre-req: any string, usually user input
	//Post-req: returns number of keywords in the string
	int checkNumOfKeyword(string&);

	//This function checks for the presences of relative day eg today, tomorrow
	//Pre-req: any string, usually user input
	//Post-req: returns true of relative day is present in string and false if otherwise
	bool checkRelativeDay(string);

	//This function checks whether the string is date or time
	//Pre-req: any string, usually either date or time string
	//Post-req: returns "date", "time" or "invalid", depending on the string
	string checkDateOrTime(string);

	//This function splits a string into words
	//Pre-req: any string
	//Post-req: returns a vector of words
	vector<string> splitToWords(string);

	//This function checks whether the string is date or time then convertsthe string to proper format required by the storage
	//Pre-req: a date or time string
	//Post-req: returns date or time in stardised format
	string convertDateTimeToString(string);

public:
	//Constructor
	//Pre-req: user input
	//Post-req: NIL
	Tokeniser(string);

	//Deconstructor
	//Pre-req: NIL
	//Post-req: NIL
	~Tokeniser();

	//This function is to get the command type of the user input
	//Pre-req: NIL
	//Post-req: returns the command type
	CommonEnum::COMMAND_TYPE getCommand();

	//This function is to get the entry extracted from user input
	//Pre-req: NIL
	//Post-req: returns the entry
	Entry* getEntry();

	//This function is to extract the part of entry to edit
	//Pre-req: NIL
	//Post-req: returns a vector containing the part of entry to be editted
	vector<string> extractEntryToEdit();

	//This function extracts the line number, following a delete command
	//Pre-req: NIL
	//Post-req: returns the line number
	int extractLineNum();

	//This function extracts string after the command
	//Pre-req: NIL
	//Post-req: returns the string without the command
	string extractKey();

	//This function formats the date from a string to a QDate
	//Pre-req: date string
	//Post-req: returns date format of QDate
	QDate formatDate(string);

	//This function checks the format of the user input
	//Pre-req: user input
	//Post-req: returns true if the format is correct and false if otherwise
	static bool checkFormat(string);
};

#endif // !_TOKENISER_H_